From: Paul Gofman <gofmanp@gmail.com>
Subject: [resend PATCH] user32: Set PAINTSTRUCT fErase field depending on the last WM_ERASEBKGND result.
Message-Id: <20200407085136.355006-1-gofmanp@gmail.com>
Date: Tue,  7 Apr 2020 11:51:36 +0300

Fixes menu update in Diablo 1.

Signed-off-by: Paul Gofman <gofmanp@gmail.com>
---
 dlls/user32/painting.c  | 26 +++++++++++-
 dlls/user32/tests/win.c | 94 +++++++++++++++++++++++++++++++++++++++++
 dlls/user32/win.h       |  1 +
 3 files changed, 120 insertions(+), 1 deletion(-)

diff --git a/dlls/user32/painting.c b/dlls/user32/painting.c
index 313c5fa1e6..6ab53a2372 100644
--- a/dlls/user32/painting.c
+++ b/dlls/user32/painting.c
@@ -725,7 +725,20 @@ static BOOL send_erase( HWND hwnd, UINT flags, HRGN client_rgn,
             {
                 /* don't erase if the clip box is empty */
                 if (type != NULLREGION)
+                {
+                    WND *wnd_ptr;
+
                     need_erase = !SendMessageW( hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0 );
+                    if ((wnd_ptr = WIN_GetPtr( hwnd )) && wnd_ptr != WND_OTHER_PROCESS && wnd_ptr != WND_DESKTOP)
+                    {
+                        if (need_erase)
+                            wnd_ptr->flags |= WIN_PS_NEED_ERASE_BKGND;
+                        else
+                            wnd_ptr->flags &= ~WIN_PS_NEED_ERASE_BKGND;
+
+                        WIN_ReleasePtr( wnd_ptr );
+                    }
+                }
             }
             if (!hdc_ret) release_dc( hwnd, hdc, TRUE );
         }
@@ -943,6 +956,7 @@ HDC WINAPI BeginPaint( HWND hwnd, PAINTSTRUCT *lps )
     BOOL erase;
     RECT rect;
     UINT flags = UPDATE_NONCLIENT | UPDATE_ERASE | UPDATE_PAINT | UPDATE_INTERNALPAINT | UPDATE_NOCHILDREN;
+    WND *wnd_ptr;
 
     HideCaret( hwnd );
 
@@ -957,7 +971,17 @@ HDC WINAPI BeginPaint( HWND hwnd, PAINTSTRUCT *lps )
         release_dc( hwnd, hdc, TRUE );
         return 0;
     }
-    lps->fErase = erase;
+
+    if (!(wnd_ptr = WIN_GetPtr( hwnd )) || wnd_ptr == WND_OTHER_PROCESS || wnd_ptr == WND_DESKTOP)
+    {
+        lps->fErase = erase;
+    }
+    else
+    {
+        lps->fErase = !!(wnd_ptr->flags & WIN_PS_NEED_ERASE_BKGND);
+        WIN_ReleasePtr( wnd_ptr );
+    }
+
     lps->rcPaint = rect;
     lps->hdc = hdc;
     return hdc;
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c
index 25d643f54a..c02af08a90 100644
--- a/dlls/user32/tests/win.c
+++ b/dlls/user32/tests/win.c
@@ -11830,6 +11830,99 @@ static void test_other_process_window(const char *argv0)
     DestroyWindow(hwnd);
 }
 
+static BOOL test_paintstruct_erase_bkgnd;
+static BOOL test_paintstruct_wm_erasebkgnd_received;
+static BOOL test_paintstruct_wm_paint_received, test_paintstruct_ferase;
+
+static LRESULT WINAPI paintstruct_erase_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    switch (msg)
+    {
+        case WM_ERASEBKGND:
+        {
+            test_paintstruct_wm_erasebkgnd_received = TRUE;
+            return test_paintstruct_erase_bkgnd;
+        }
+
+        case WM_PAINT:
+        {
+            PAINTSTRUCT ps;
+            HDC hdc;
+
+            test_paintstruct_wm_paint_received = TRUE;
+            hdc = BeginPaint(hwnd, &ps);
+            ok(!!hdc, "Null hdc.\n");
+            test_paintstruct_ferase = ps.fErase;
+            EndPaint(hwnd, &ps);
+            return 0;
+        }
+    }
+    return DefWindowProcA(hwnd, msg, wparam, lparam);
+}
+
+static void test_paintstruct_erase(void)
+{
+    WNDCLASSA cls;
+    HWND hwnd;
+    BOOL ret;
+
+    cls.style = 0;
+    cls.lpfnWndProc = paintstruct_erase_window_procA;
+    cls.cbClsExtra = 0;
+    cls.cbWndExtra = 0;
+    cls.hInstance = GetModuleHandleA(0);
+    cls.hIcon = 0;
+    cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
+    cls.hbrBackground = GetStockObject(WHITE_BRUSH);
+    cls.lpszMenuName = NULL;
+    cls.lpszClassName = "paintstruct_erase_class";
+    ret = RegisterClassA(&cls);
+    ok(ret, "Failed to register a test class.\n");
+
+    test_paintstruct_wm_paint_received = test_paintstruct_wm_erasebkgnd_received = FALSE;
+    test_paintstruct_erase_bkgnd = FALSE;
+    hwnd = CreateWindowExA(0, "paintstruct_erase_class", NULL, WS_POPUP | WS_VISIBLE,
+            100, 100, 100, 100, 0, 0, NULL, NULL);
+    ok(!!hwnd, "CreateWindowEx failed.\n");
+
+    flush_events(TRUE);
+    ok(test_paintstruct_wm_erasebkgnd_received, "WM_ERASEBKGND not received.\n");
+    ok(test_paintstruct_wm_paint_received, "WM_PAINT not received.\n");
+    ok(test_paintstruct_ferase, "Unexpected fErase %#x.\n", test_paintstruct_ferase);
+
+    test_paintstruct_wm_paint_received = test_paintstruct_wm_erasebkgnd_received = FALSE;
+    RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
+    flush_events(TRUE);
+    ok(!test_paintstruct_wm_erasebkgnd_received, "WM_ERASEBKGND received.\n");
+    ok(test_paintstruct_wm_paint_received, "WM_PAINT not received.\n");
+    ok(test_paintstruct_ferase, "Unexpected fErase %#x.\n", test_paintstruct_ferase);
+
+    test_paintstruct_wm_paint_received = test_paintstruct_wm_erasebkgnd_received = FALSE;
+    RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
+    flush_events(TRUE);
+    ok(!test_paintstruct_wm_erasebkgnd_received, "WM_ERASEBKGND received.\n");
+    ok(test_paintstruct_wm_paint_received, "WM_PAINT not received.\n");
+    ok(test_paintstruct_ferase, "Unexpected fErase %#x.\n", test_paintstruct_ferase);
+
+    test_paintstruct_erase_bkgnd = TRUE;
+    test_paintstruct_wm_paint_received = test_paintstruct_wm_erasebkgnd_received = FALSE;
+    RedrawWindow(hwnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE);
+    flush_events(TRUE);
+    ok(test_paintstruct_wm_erasebkgnd_received, "WM_ERASEBKGND not received.\n");
+    ok(test_paintstruct_wm_paint_received, "WM_PAINT not received.\n");
+    ok(!test_paintstruct_ferase, "Unexpected fErase %#x.\n", test_paintstruct_ferase);
+
+    test_paintstruct_wm_paint_received = test_paintstruct_wm_erasebkgnd_received = FALSE;
+    RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
+    flush_events(TRUE);
+    ok(!test_paintstruct_wm_erasebkgnd_received, "WM_ERASEBKGND received.\n");
+    ok(test_paintstruct_wm_paint_received, "WM_PAINT not received.\n");
+    ok(!test_paintstruct_ferase, "Unexpected fErase %#x.\n", test_paintstruct_ferase);
+
+    DestroyWindow(hwnd);
+    UnregisterClassA("paintstruct_erase_class", GetModuleHandleA(NULL));
+}
+
 START_TEST(win)
 {
     char **argv;
@@ -11995,6 +12088,7 @@ START_TEST(win)
     test_window_placement();
     test_arrange_iconic_windows();
     test_other_process_window(argv[0]);
+    test_paintstruct_erase();
 
     /* add the tests above this line */
     if (hhook) UnhookWindowsHookEx(hhook);
diff --git a/dlls/user32/win.h b/dlls/user32/win.h
index 1f51fd6331..eecfa20eea 100644
--- a/dlls/user32/win.h
+++ b/dlls/user32/win.h
@@ -79,6 +79,7 @@ typedef struct tagWND
 #define WIN_CHILDREN_MOVED        0x0040 /* children may have moved, ignore stored positions */
 #define WIN_HAS_IME_WIN           0x0080 /* the window has been registered with imm32 */
 #define WIN_IS_IN_ACTIVATION      0x0100 /* the window is in an activation process */
+#define WIN_PS_NEED_ERASE_BKGND   0x0200 /* Need to set fErase in PAINTSTRUCT */
 
   /* Window functions */
 extern HWND get_hwnd_message_parent(void) DECLSPEC_HIDDEN;

-- 
2.25.2

